﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DisplayString.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Types
{
  using System;
  using System.ComponentModel;
  using System.Globalization;
  using System.Text;

  using Lextm.SharpSnmpLib;

  /// <summary>
  /// Converts DisplayString to string and string to octetstring.
  /// </summary>
  /// <remarks>
  /// 	DisplayString ::= TEXTUAL-CONVENTION
  ///	DISPLAY-HINT 
  ///		"255a"
  ///	STATUS current
  ///	DESCRIPTION
  ///		"Represents textual information taken from the NVT ASCII
  ///		character set, as defined in pages 4, 10-11 of RFC 854.
  ///		
  ///		To summarize RFC 854, the NVT ASCII repertoire specifies:
  ///		
  ///		  - the use of character codes 0-127 (decimal)
  ///		
  ///		  - the graphics characters (32-126) are interpreted as
  ///		    US ASCII
  ///		
  ///		  - NUL, LF, CR, BEL, BS, HT, VT and FF have the special
  ///		    meanings specified in RFC 854
  ///		
  ///		  - the other 25 codes have no standard interpretation
  ///		
  ///		  - the sequence 'CR LF' means newline
  ///		
  ///		  - the sequence 'CR NUL' means carriage-return
  ///		
  ///		  - an 'LF' not preceded by a 'CR' means moving to the
  ///		    same column on the next line.
  ///		
  ///		  - the sequence 'CR x' for any x other than LF or NUL is
  ///		    illegal.  (Note that this also means that a string may
  ///		    end with either 'CR LF' or 'CR NUL', but not with CR.)
  ///		
  ///		Any object defined using this syntax may not exceed 255
  ///		characters in length."
  ///	SYNTAX OCTET STRING (SIZE (0..255))
  ///</remarks>
  public sealed class DisplayString : TypeConverter
  {
    #region Public Methods and Operators

    /// <summary>
    /// The can convert from.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="sourceType">
    /// The source type.
    /// </param>
    /// <returns>
    /// The System.Boolean.
    /// </returns>
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
      if (sourceType == typeof(string))
      {
        return true;
      }

      return base.CanConvertFrom(context, sourceType);
    }

    /// <summary>
    /// The can convert to.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="destinationType">
    /// The destination type.
    /// </param>
    /// <returns>
    /// The System.Boolean.
    /// </returns>
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
      if (destinationType == typeof(string))
      {
        return true;
      }

      return base.CanConvertTo(context, destinationType);
    }

    /// <summary>
    /// Converts a <see cref="string"/> to a DisplayString encoded <see cref="OctetString"/>.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="culture">
    /// Using culture.
    /// </param>
    /// <param name="value">
    /// The <see cref="string"/> value.
    /// </param>
    /// <returns>
    /// A <see cref="OctetString"/> encoded as DisplayString as defined in SNMPv2-TC.
    /// </returns>
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
      if (!(value is string))
      {
        return base.ConvertFrom(context, culture, value);
      }

      return new OctetString((string)value);
    }

    /// <summary>
    /// Converts a <see cref="OctetString"/> encoded as DateAndTime (per SNMPv2-TC definition) to a <see cref="DateTime"/>.
    /// </summary>
    /// <param name="context">
    /// The context.
    /// </param>
    /// <param name="culture">
    /// Using culture.
    /// </param>
    /// <param name="value">
    /// The <see cref="OctetString"/> to be converted.
    /// </param>
    /// <param name="destinationType">
    /// A <see cref="DateTime"/>.
    /// </param>
    /// <returns>
    /// A <see cref="DateTime"/> either with timezone info or localtime depending on the inparam <see cref="OctetString"/> length (8 or 11).
    /// </returns>
    public override object ConvertTo(
      ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
      if (!(value is OctetString) || (destinationType != typeof(string)))
      {
        return base.ConvertTo(context, culture, value, destinationType);
      }

      var octetString = (OctetString)value;

      return Encoding.ASCII.GetString(octetString.GetRaw());
    }

    #endregion
  }
}